package com.ksana.bean.factory.support;

import cn.hutool.core.lang.Assert;
import com.ksana.bean.BeanException;
import com.ksana.bean.factory.DisposableBean;
import com.ksana.bean.factory.config.SingletonBeanRegistry;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    private Map<String, Object> singletonObjects = new HashMap<>();
    private Map<String, Object> disposableBeans = new LinkedHashMap<>();

    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws BeanException {
        Assert.notNull(beanName, "bean 的名字不能为空");
        Assert.notNull(singletonObject, "singleton Object 不能为空");
        Object object = singletonObjects.get(beanName);
        if (object != null) {
            throw new BeanException("实例已经存在");
        }
        singletonObjects.put(beanName, singletonObject);
        if (singletonObject instanceof DisposableBean) {
            registerDisposableBeans(beanName, (DisposableBean) singletonObject);
        }
    }

    @Override
    public Object getSingleton(String beanName) {
        return singletonObjects.get(beanName);
    }

    public void registerDisposableBeans(String beanName, DisposableBean bean) {
        synchronized (this.disposableBeans) {
            disposableBeans.put(beanName, bean);
        }
    }

    public void destroySingletons() {
        String[] disposableBeanNames;
        synchronized (this.disposableBeans) {
            disposableBeanNames = this.disposableBeans.keySet().toArray(new String[]{});
        }

        for (Integer i = 0; i < disposableBeanNames.length; i++) {
            destroySingleton(disposableBeanNames[i]);
        }

        this.singletonObjects.clear();
    }

    public void destroySingleton(String beanName) {
        singletonObjects.remove(beanName);
        DisposableBean bean;
        synchronized (this.disposableBeans) {
            bean = (DisposableBean) this.disposableBeans.remove(beanName);
        }
        destroyBean(beanName, bean);
    }

    protected void destroyBean(String beanName, DisposableBean bean) {
        if (bean != null) {
            bean.destroy();
        }
    }
}
